package com.liuxinlong.common.uploadSMBJ;

import com.liuxinlong.constant.RegionConstants;
import com.liuxinlong.constant.TimeFormatConstants;
import com.liuxinlong.modules.entity.ShareFile;
import com.liuxinlong.utils.FileUtils;
import com.liuxinlong.utils.TimeUtils;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
import com.hierynomus.mssmb2.SMB2ShareAccess;
import com.hierynomus.smbj.SMBClient;
import com.hierynomus.smbj.SmbConfig;
import com.hierynomus.smbj.auth.AuthenticationContext;
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.File;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * SMBJ文件上传下载
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2021-06-14
 */
@Service
@Slf4j
public class SMBJRequestService implements SMBJInterface {
    @Autowired
    private SMBJConfig smbjConfig;

    /**
     * 连接共享盘更新文件目录
     *
     * @param host ip
     * @return 文件目录
     */
    public List<ShareFile> connect(String host) {
        SMBClient client = new SMBClient();
        List<ShareFile> newFileList = new ArrayList<>();
        try (Connection connection = client.connect(host)) {
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), "");
            Session session = connection.authenticate(ac);

            // Connect to Share
            // \\192.168.2.3\temp\临时数据\共享目录    对应“temp”
            try (DiskShare share = (DiskShare) session.connectShare(smbjConfig.getHotSrcDir())) {
                // \\192.168.2.3\temp\临时数据\共享目录    对应“\临时数据\共享目录”  \ECN电热\2022\5月
                String path = smbjConfig.getHotDistDir();
                List<ShareFile> fileList = new ArrayList<>();
                newFileList = getFileList(share, path, fileList, true);
                int i = 1;
                for (ShareFile shareFile : newFileList) {
                    shareFile.setRegion(RegionConstants.WPCNJ);
//                    log.info("File" + i + ": " + shareFile.toString());
                    i++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return newFileList;
    }

    /**
     * 连接共享盘更新文件目录
     *
     * @param host ip
     * @return 文件目录
     */
    public List<ShareFile> connectCEP(String host) {
        SMBClient client = new SMBClient();
        List<ShareFile> newFileList = new ArrayList<>();

        try (Connection connection = client.connect(host)) {
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), "");
            Session session = connection.authenticate(ac);

            // Connect to Share
            // \\192.168.2.3\temp\临时数据\共享目录    对应“temp”
            try (DiskShare share = (DiskShare) session.connectShare(smbjConfig.getCepSrcDir())) {
                // \\192.168.2.3\temp\临时数据\共享目录    对应“\临时数据\共享目录”  \ECN电热\2022\5月
                String path = smbjConfig.getCepDistDir();
                List<ShareFile> fileList = new ArrayList<>();
                newFileList = getFileList(share, path, fileList, false);
                int i = 1;
                for (ShareFile shareFile : newFileList) {
                    shareFile.setRegion(RegionConstants.SWTNJ);
//                    log.info("File" + i + ": " + shareFile.toString());
                    i++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return newFileList;
    }

    /**
     * 获取文件列表
     *
     * @param share    DiskShare
     * @param path     路径
     * @param fileList 文件列表
     * @param wpcFlag  wpc标识
     * @return 文件列表
     */
    private List<ShareFile> getFileList(DiskShare share, String path, List<ShareFile> fileList, boolean wpcFlag) {
        for (FileIdBothDirectoryInformation f : share.list(path)) {
            String fileName = f.getFileName();
            String newPath = path + "\\" + fileName;
            if (StringUtils.equals(fileName, ".") || StringUtils.equals(fileName, "..")
                    || StringUtils.equals(fileName, "检验类原文件") || StringUtils.equals(fileName, "质量记录原文件")
                    || StringUtils.equals(fileName, "检验文件盖章版本") || StringUtils.equals(fileName, "锅炉质量证明书自制件图纸")
                    || StringUtils.equals(fileName, "ECN电控发布") || StringUtils.equals(fileName, "电控软件SC发布存档")
                    || StringUtils.equals(fileName, "SOP工艺原文件") || StringUtils.equals(fileName, "终极最全")
                    || StringUtils.equals(fileName, "A级") || StringUtils.equals(fileName, "工艺文件盖章版本")
//                    || StringUtils.contains(fileName, "4005-")
                    || StringUtils.equals(fileName, "历史ECN")
                    || StringUtils.equals(fileName, "WPC ECN") || StringUtils.equals(fileName, "ECN跟踪")
            ) {
                continue;
            }
            if (StringUtils.containsIgnoreCase(fileName, ".pdf")) {
                String ecnNo = wpcFlag ? fileName.substring(0, 9) : fileName.contains("N-R-") ? fileName.substring(0, 11) : fileName.substring(0, 9);
                ShareFile shareFile = new ShareFile();
                shareFile.setFileName(fileName);
                shareFile.setFilePath(newPath);
                shareFile.setSourceType(1);
                shareFile.setSourceNo(ecnNo);
                shareFile.setOperateTime(TimeUtils.formatTime(f.getChangeTime().toDate(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS));
                fileList.add(shareFile);
            } else if (StringUtils.containsIgnoreCase(fileName, ".")) {
            } else {
                getFileList(share, newPath, fileList, wpcFlag);
            }
        }
        return fileList;
    }


    /**
     * 连接图纸文档共享盘
     *
     * @param host 地址
     * @return 文件列表
     */
    public List<ShareFile> connectDraw(String host) {
        SMBClient client = new SMBClient();
        List<ShareFile> fileList = new ArrayList<>();
        try (Connection connection = client.connect(host)) {
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), "");
            Session session = connection.authenticate(ac);

            // Connect to Share
            // \\192.168.2.3\temp\临时数据\共享目录    对应“temp”
            try (DiskShare share = (DiskShare) session.connectShare("pmip_PDF")) {
                // \\192.168.2.3\temp\临时数据\共享目录    对应“\临时数据\共享目录”
                int i = 1;
                getDrawFileList(share, "\\", fileList, i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return fileList;
    }

    /**
     * 获取文件列表
     *
     * @param share    share
     * @param path     路径
     * @param fileList 文件列表
     * @param sort     排序
     * @return 文件列表
     */
    private List<ShareFile> getDrawFileList(DiskShare share, String path, List<ShareFile> fileList, int sort) {
//        DiskShare share = (DiskShare) session.connectShare(path);
        for (FileIdBothDirectoryInformation f : share.list(path)) {
            String fileName = f.getFileName();
            String newPath = StringUtils.equals(path, "\\") ? "\\" + fileName : path + "\\" + fileName;
            if (StringUtils.equals(f.getFileName(), ".") || StringUtils.equals(f.getFileName(), "..")) {
                continue;
            }
            if (f.getFileAttributes() == 16) {
                getDrawFileList(share, newPath, fileList, sort);
                continue;
            }
            if (fileName.length() > 20) {
                continue;
            }
            String drawNo = fileName.split("\\.")[0];
            ShareFile shareFile = new ShareFile();
            shareFile.setFileName(fileName);
            shareFile.setFilePath(newPath);
            shareFile.setSourceType(2);
            shareFile.setSourceNo(drawNo);
            shareFile.setOperateTime(TimeUtils.formatTime(f.getChangeTime().toDate(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS));
            shareFile.setRegion(RegionConstants.WPCNJ);
            fileList.add(shareFile);

            sort++;
        }
        return fileList;
    }

    /**
     * 查看共享盘文件
     *
     * @param shareFile 共享文件信息
     * @param response  返回体
     */
    public void viewFile(ShareFile shareFile, HttpServletResponse response) {

        // 设置超时时间(可选)
        SmbConfig config = SmbConfig.builder().withTimeout(120, TimeUnit.SECONDS)
                .withTimeout(120, TimeUnit.SECONDS) // 超时设置读，写和Transact超时（默认为60秒）
                .withSoTimeout(180, TimeUnit.SECONDS) // Socket超时（默认为0秒）
                .build();

        // 如果不设置超时时间	SMBClient client = new SMBClient();
        SMBClient client = new SMBClient(config);

        boolean wpcFlag = StringUtils.equals(shareFile.getRegion(), RegionConstants.WPCNJ);
        try {
            Connection connection = client.connect(shareFile.getSourceType() == 1 ? (wpcFlag ? smbjConfig.getHotHost() : smbjConfig.getCepHost()) : smbjConfig.getDrawHost());    // 如:123.123.123.123
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), smbjConfig.getDomain());
            Session session = connection.authenticate(ac);

            // 连接共享文件夹
            DiskShare share = (DiskShare) session.connectShare(shareFile.getSourceType() == 1 ? (wpcFlag ? smbjConfig.getHotSrcDir() : smbjConfig.getCepSrcDir()): "pmip_PDF");
            String filePath = shareFile.getFilePath();
            if (share.fileExists(filePath)) {
                File smbFileRead = share.openFile(filePath, EnumSet.of(AccessMask.GENERIC_READ), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null);

                InputStream fileInputStream = smbFileRead.getInputStream();
                response.setHeader("Content-Disposition", "attachment;fileName=" + shareFile.getFileName());
                response.setContentType("multipart/form-data");
                OutputStream outputStream = response.getOutputStream();
                IOUtils.write(IOUtils.toByteArray(fileInputStream), outputStream);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (client != null) {
                client.close();
            }
        }
    }

    /**
     * 连接图纸文档共享盘复制文档到本地服务器
     *
     * @return 成功与失败路径列表
     */
    public Map<String, Object> copyDraw() {
        Map<String, Object> resultMap = new HashMap<>();
        // 设置超时时间(可选)
        SmbConfig config = SmbConfig.builder().withTimeout(120, TimeUnit.SECONDS)
                .withTimeout(120, TimeUnit.SECONDS) // 超时设置读，写和Transact超时（默认为60秒）
                .withSoTimeout(180, TimeUnit.SECONDS) // Socket超时（默认为0秒）
                .build();

        SMBClient client = new SMBClient(config);

        List<String> successList = new ArrayList<>();
        List<String> rmFailedList = new ArrayList<>();

        try (Connection connection = client.connect(smbjConfig.getDrawHost())) {
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), "");
            Session session = connection.authenticate(ac);

            // 目标路径
            java.io.File localFile = new java.io.File(smbjConfig.getDrawLocalDir());
            // 如果文件目录不存在，就执行创建
            if (!localFile.isDirectory()) {
                localFile.mkdirs();
            }

            List<ShareFile> filePathList = new ArrayList<>();

            // Connect to Share
            // \\192.168.2.3\temp\临时数据\共享目录    对应“temp”
            try (DiskShare share = (DiskShare) session.connectShare(smbjConfig.getDrawSrcDir())) {
                // \\192.168.2.3\temp\临时数据\共享目录    对应“\临时数据\共享目录”
                int i = 1;
                filePathList = getDrawFileList(share, "\\", filePathList);
//                for (FileIdBothDirectoryInformation f : share.list("\\", "*")) {
//                    String fileName = f.getFileName();
//                    if (StringUtils.equals(fileName, ".") || StringUtils.equals(fileName, "..")){
//                        continue;
//                    }
//                    log.info("File " + i + ": " + fileName);
//                    ShareFile file = new ShareFile();
//                    file.setFilePath(fileName);
//                    file.setFileName(f.getFileName());
//                    filePathList.add(file);
//                    i++;
//                    if(i>100) {
//                        break;
//                    }
//                }

                for (ShareFile file : filePathList) {
                    String filePath = file.getFilePath();
                    String dstPath = smbjConfig.getDrawLocalDir() + file.getFileName();

                    FileOutputStream fos = new FileOutputStream(dstPath);
                    BufferedOutputStream bos = new BufferedOutputStream(fos);

                    if (share.fileExists(filePath)) {
                        log.info("正在下载文件:" + file.getFileName());

                        File smbFileRead = share.openFile(filePath, EnumSet.of(AccessMask.GENERIC_ALL), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null);

                        InputStream in = smbFileRead.getInputStream();
                        byte[] buffer = new byte[4096];
                        int len = 0;
                        while ((len = in.read(buffer, 0, buffer.length)) != -1) {
                            bos.write(buffer, 0, len);
                        }

                        bos.flush();
                        bos.close();
                        log.info("文件下载成功");
                        log.info("==========================");

                        try {
//                            share.rm(smbFileRead.getPath());
//                            smbFileRead.deleteOnClose();
                            successList.add(smbFileRead.getPath());
                        } catch (Exception e) {
                            e.printStackTrace();
                            rmFailedList.add(smbFileRead.getPath());
                        }
                        i++;
                        if (i > 100) {
                            break;
                        }
                    } else {
                        log.info("文件不存在");
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (client != null) {
                client.close();
            }
        }
        resultMap.put("successNum", successList.size());
        resultMap.put("failedNum", rmFailedList.size());
        return resultMap;
    }

    /**
     * 共享盘上传文件
     */
    public void uploadDrawFile() {
        // 设置超时时间(可选)
        SmbConfig config = SmbConfig.builder().withTimeout(120, TimeUnit.SECONDS)
                .withTimeout(120, TimeUnit.SECONDS) // 超时设置读，写和Transact超时（默认为60秒）
                .withSoTimeout(180, TimeUnit.SECONDS) // Socket超时（默认为0秒）
                .build();

        // 如果不设置超时时间	SMBClient client = new SMBClient();
        SMBClient client = new SMBClient(config);
        OutputStream shareOs = null;
        DiskShare diskShare = null;

        try (Connection connection = client.connect(smbjConfig.getDrawHost())) {
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), "");
            Session session = connection.authenticate(ac);

            List<ShareFile> filePathList = FileUtils.getFilePathList(smbjConfig.getDrawLocalDir());
            int i = 1;
            for (ShareFile shareFile : filePathList) {
                if (i > 300) {
                    break;
                }
                // Connect to Share
                // \\192.168.2.3\temp\临时数据\共享目录    对应“temp”
                try (DiskShare share = (DiskShare) session.connectShare(smbjConfig.getDrawSrcDir())) {
                    log.info("正在上传文件:" + shareFile.getFileName());
                    java.io.File inputFile = new java.io.File(shareFile.getFilePath());
                    FileInputStream fis = new FileInputStream(inputFile);
                    SMB2CreateDisposition value = SMB2CreateDisposition.FILE_CREATE;
                    if (share.fileExists(shareFile.getFileName())) {
                        value = SMB2CreateDisposition.FILE_OVERWRITE_IF;
                    }
                    File smbFileShare = share.openFile(shareFile.getFileName(), EnumSet.of(AccessMask.GENERIC_ALL),
                            null, SMB2ShareAccess.ALL, value, null);
                    shareOs = smbFileShare.getOutputStream();

                    byte[] buffer = new byte[4096];
                    int len = 0;
                    while ((len = fis.read(buffer, 0, buffer.length)) != -1) {
                        shareOs.write(buffer, 0, len);
                    }

                    shareOs.flush();
                    log.info("文件上传成功");
                    log.info("==========================");
                    i++;
                } catch (Exception e) {
                    e.printStackTrace();
                    log.info("文件不存在");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (client != null) {
                client.close();
            }
            try {
                if (null != shareOs) {
                    shareOs.close();
                }
                if (null != diskShare) {
                    diskShare.close();
                }
                if (null != client) {
                    client.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }

        }
    }

    /**
     * 共享盘下载文件
     *
     * @param shareFile 文件信息
     */
    public void downloadFile(ShareFile shareFile) {
        // 设置超时时间(可选)
        SmbConfig config = SmbConfig.builder().withTimeout(120, TimeUnit.SECONDS)
                .withTimeout(120, TimeUnit.SECONDS) // 超时设置读，写和Transact超时（默认为60秒）
                .withSoTimeout(180, TimeUnit.SECONDS) // Socket超时（默认为0秒）
                .build();

        // 如果不设置超时时间	SMBClient client = new SMBClient();
        SMBClient client = new SMBClient(config);

        boolean wpcFlag = StringUtils.equals(shareFile.getRegion(), RegionConstants.WPCNJ);
        try {
            Connection connection = client.connect(wpcFlag ? smbjConfig.getHotHost() : smbjConfig.getCepHost());    // 如:123.123.123.123
            AuthenticationContext ac = new AuthenticationContext(smbjConfig.getUsername(), smbjConfig.getPassword().toCharArray(), smbjConfig.getDomain());
            Session session = connection.authenticate(ac);

            // 连接共享文件夹
            DiskShare share = (DiskShare) session.connectShare(wpcFlag ? smbjConfig.getHotSrcDir() : smbjConfig.getCepSrcDir());

            String filePath = shareFile.getFilePath();
            String dstRoot = "/down/";    // 如: D:/smd2/

            String dstPath = dstRoot + shareFile.getFileName();

            FileOutputStream fos = new FileOutputStream(dstPath);
            BufferedOutputStream bos = new BufferedOutputStream(fos);

            if (share.fileExists(filePath)) {
                log.info("正在下载文件:" + shareFile.getFileName());

                File smbFileRead = share.openFile(filePath, EnumSet.of(AccessMask.GENERIC_READ), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null);
                InputStream in = smbFileRead.getInputStream();
                byte[] buffer = new byte[4096];
                int len = 0;
                while ((len = in.read(buffer, 0, buffer.length)) != -1) {
                    bos.write(buffer, 0, len);
                }

                bos.flush();
                bos.close();

                log.info("文件下载成功");
                log.info("==========================");
            } else {
                log.info("文件不存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (client != null) {
                client.close();
            }
        }
    }

    /**
     * 获取文件列表
     *
     * @param share    DiskShare
     * @param path     路径
     * @param fileList 文件列表
     * @return 文件列表
     */
    private List<ShareFile> getDrawFileList(DiskShare share, String path, List<ShareFile> fileList) {
        for (FileIdBothDirectoryInformation f : share.list(path)) {
            String fileName = f.getFileName();
            String newPath = path + "\\" + fileName;
            if (StringUtils.equals(fileName, ".") || StringUtils.equals(fileName, "..")) {
                continue;
            }
            if (StringUtils.containsIgnoreCase(fileName, ".")) {
                String drawNo = fileName.substring(0, 9);
                ShareFile shareFile = new ShareFile();
                shareFile.setFileName(fileName);
                shareFile.setFilePath(newPath);
                shareFile.setSourceType(1);
                shareFile.setSourceNo(drawNo);
                shareFile.setOperateTime(TimeUtils.formatTime(f.getChangeTime().toDate(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS));
                fileList.add(shareFile);
            } else if (StringUtils.containsIgnoreCase(fileName, ".")) {
            } else {
                getDrawFileList(share, newPath, fileList);
            }
        }
        return fileList;
    }
}
